home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Devices and Hardware / Velocity Engine / VelEng Wavelet / source / QTUtilities.c < prev    next >
Encoding:
Text File  |  2000-09-28  |  55.3 KB  |  1,924 lines  |  [TEXT/CWIE]

  1. //////////
  2. //
  3. //    File:        QTUtilities.c
  4. //
  5. //    Contains:    Some utilities for working with QuickTime movies.
  6. //                All utilities start with the prefix "QTUtils_".
  7. //
  8. //    Copyright:    © 1996-1999 by Apple Computer, Inc., all rights reserved.
  9. //
  10. //    Change History (most recent first):
  11. //
  12. //       <23>         03/22/99    rtm        updated connection speed code to use constants/data types now in Movies.h
  13. //       <22>         03/11/99    rtm        moved _GetControllerType and _SetControllerType from QTVRUtilities to here;
  14. //                                    added QTUtils_ChangeControllerType
  15. //       <21>         02/03/99    rtm        moved non-QTVR-specific utilities from QTVRUtilities to here
  16. //       <20>         01/26/99    rtm        added QTUtils_ConvertCToPascalString; removed "\p" from any constant strings
  17. //       <19>         01/25/99    rtm        #define'd away QTUtils_GetUsersContentRating and siblings, since content rating
  18. //                                    capability is not in latest feature set
  19. //       <18>         12/09/98    rtm        added QTUtils_GetUsersContentRating
  20. //       <17>         11/18/98    rtm        added QTUtils_GetFrameCount
  21. //       <16>         10/27/98    rtm        added QTUtils_MakeMovieLoop
  22. //       <15>         09/14/98    rtm        added QTUtils_GetUsersConnectionSpeed and QTUtils_SetUsersConnectionSpeed
  23. //       <14>         06/24/98    rtm        added QTUtils_GetMaxWindowDepth and QTUtils_GetMaxScreenDepth
  24. //       <13>         06/04/98    rtm        added QTUtils_DeleteAllReferencesToTrack
  25. //       <12>         05/28/98    rtm        added some typecasting to minimize MSDev compiler warnings
  26. //       <11>         05/19/98    rtm        added QTUtils_MovieHasTimeCodeTrack
  27. //       <10>         05/04/98    rtm        added QTUtils_GetTrackName, QTUtils_SetTrackName, QTUtils_MakeTrackNameByType,
  28. //                                    QTUtils_IsImageFile, and QTUtils_IsMovieFile
  29. //       <9>         02/28/98    rtm        fixed QTUtils_GetMovieFileLoopingInfo and the like
  30. //       <8>         01/14/98    rtm        added QTUtils_ConvertFloatToBigEndian
  31. //       <7>         12/19/97    rtm        added QTUtils_AddUserDataTextToMovie and associated routines;
  32. //                                    added QTUtils_GetMovieFileLoopingInfo and the like
  33. //       <6>         11/06/97    rtm        added QTUtils_MakeSampleDescription
  34. //       <5>         10/29/97    rtm        modified QTUtils_IsMediaTypeInMovie and similar routines to use GetMovieIndTrackType
  35. //       <4>         10/27/97    rtm        added QTUtils_HasQuickTimeVideoEffects
  36. //       <3>         10/17/97    rtm        added QTUtils_MovieHasSoundTrack
  37. //       <2>         09/23/97    rtm        added endian adjustment to QTUtils_PrintMoviePICT
  38. //       <1>         09/10/97    rtm        first file
  39. //       
  40. //////////
  41. /*
  42.     Disclaimer:    IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
  43.                 ("Apple") in consideration of your agreement to the following terms, and your
  44.                 use, installation, modification or redistribution of this Apple software
  45.                 constitutes acceptance of these terms.  If you do not agree with these terms,
  46.                 please do not use, install, modify or redistribute this Apple software.
  47.  
  48.                 In consideration of your agreement to abide by the following terms, and subject
  49.                 to these terms, Apple grants you a personal, non-exclusive license, under Apple’s
  50.                 copyrights in this original Apple software (the "Apple Software"), to use,
  51.                 reproduce, modify and redistribute the Apple Software, with or without
  52.                 modifications, in source and/or binary forms; provided that if you redistribute
  53.                 the Apple Software in its entirety and without modifications, you must retain
  54.                 this notice and the following text and disclaimers in all such redistributions of
  55.                 the Apple Software.  Neither the name, trademarks, service marks or logos of
  56.                 Apple Computer, Inc. may be used to endorse or promote products derived from the
  57.                 Apple Software without specific prior written permission from Apple.  Except as
  58.                 expressly stated in this notice, no other rights or licenses, express or implied,
  59.                 are granted by Apple herein, including but not limited to any patent rights that
  60.                 may be infringed by your derivative works or by other works in which the Apple
  61.                 Software may be incorporated.
  62.  
  63.                 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
  64.                 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
  65.                 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  66.                 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
  67.                 COMBINATION WITH YOUR PRODUCTS.
  68.  
  69.                 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
  70.                 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  71.                 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  72.                 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
  73.                 OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
  74.                 (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
  75.                 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  76. */
  77.  
  78. //////////
  79. //
  80. // header files
  81. //
  82. //////////
  83.  
  84. #ifndef __QTUtilities__
  85. #include "QTUtilities.h"
  86.  
  87.  
  88. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  89. //
  90. // General utilities.
  91. //
  92. // Use these functions to get information about the availability/features of QuickTime or other services.
  93. //
  94. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  95.  
  96. //////////
  97. //
  98. // QTUtils_TrapAvailable
  99. // Check to see whether a given trap is implemented. This is based on IM: Operating System Utilities (p. 8-22).
  100. //
  101. //////////
  102.  
  103. #if TARGET_OS_MAC
  104. Boolean QTUtils_TrapAvailable (short theTrapWord)
  105. {
  106.     TrapType        myTrapType;
  107.     short            myNumToolboxTraps;
  108.     
  109.     // determine whether this is a Toolbox or an Operating System trap
  110.     if ((theTrapWord & 0x0800) > 0)
  111.         myTrapType = ToolTrap;
  112.     else
  113.         myTrapType = OSTrap;
  114.  
  115.     if (myTrapType == ToolTrap) {
  116.         theTrapWord = theTrapWord & 0x07FF;
  117.         
  118.         if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap))
  119.             myNumToolboxTraps = 0x0200;
  120.         else
  121.             myNumToolboxTraps = 0x0400;
  122.             
  123.         if (theTrapWord >= myNumToolboxTraps)
  124.             theTrapWord = _Unimplemented;
  125.     }
  126.  
  127.     return(NGetTrapAddress(theTrapWord, myTrapType) != NGetTrapAddress(_Unimplemented, ToolTrap));
  128. }
  129. #endif
  130.  
  131.  
  132. //////////
  133. //
  134. // QTUtils_IsQuickTimeInstalled
  135. // Is QuickTime installed?
  136. //
  137. //////////
  138.  
  139. Boolean QTUtils_IsQuickTimeInstalled (void) 
  140. {
  141.     Boolean     myQTAvail = false;
  142.     long        myAttrs;
  143.     OSErr         myErr = noErr;
  144.  
  145.     myErr = Gestalt(gestaltQuickTime, &myAttrs);
  146.     if (myErr == noErr)
  147.         myQTAvail = true;
  148.  
  149.     return(myQTAvail);
  150. }
  151.  
  152.  
  153. //////////
  154. //
  155. // QTUtils_IsQuickTimeCFMInstalled
  156. // Are the QuickTime CFM libraries installed?
  157. //
  158. //////////
  159.  
  160. #if TARGET_OS_MAC
  161. #ifdef powerc
  162. Boolean QTUtils_IsQuickTimeCFMInstalled (void) 
  163. {
  164.     Boolean     myQTCFMAvail = false;
  165.     long        myAttrs;
  166.     OSErr         myErr = noErr;
  167.  
  168.     // test whether the library is registered.
  169.     myErr = Gestalt(gestaltQuickTimeFeatures, &myAttrs);
  170.     if (myErr == noErr)
  171.         if (myAttrs & (1L << gestaltPPCQuickTimeLibPresent))
  172.             myQTCFMAvail = true;
  173.  
  174.     // test whether a function is available (the library is not moved from the Extension folder);
  175.     // this is the trick to be used when testing if a function is available via CFM
  176.     if (!CompressImage)
  177.         myQTCFMAvail = false;     
  178.  
  179.     return(myQTCFMAvail);
  180. }
  181. #endif    // powerc
  182. #endif
  183.  
  184.  
  185. //////////
  186. //
  187. // QTUtils_GetQTVersion
  188. // Get the version of QuickTime installed.
  189. // The high-order word of the returned long integer contains the version number,
  190. // so you can test a version like this:
  191. //
  192. //        if (((QTUtils_GetQTVersion() >> 16) & 0xffff) >= 0x0210)        // we require QT 2.1 or greater
  193. //            return;
  194. //
  195. //////////
  196.  
  197. long QTUtils_GetQTVersion (void) 
  198. {
  199.     long         myVersion = 0L;
  200.     OSErr         myErr = noErr;
  201.  
  202.     myErr = Gestalt(gestaltQuickTime, &myVersion);
  203.     if (myErr == noErr)
  204.         return(myVersion);
  205.     else
  206.         return(0L);
  207. }
  208.  
  209.  
  210. //////////
  211. //
  212. // QTUtils_HasQuickTimeVideoEffects
  213. // Does the installed version of QuickTime support video effects?
  214. //
  215. // Note: this is a pretty cheesy way of determining whether video effects are available.
  216. //
  217. //////////
  218.  
  219. Boolean QTUtils_HasQuickTimeVideoEffects (void) 
  220. {
  221.     return(((QTUtils_GetQTVersion() >> 16) & 0xffff) >= kQTVideoEffectsMinVers);
  222. }
  223.  
  224.  
  225. //////////
  226. //
  227. // QTUtils_HasFullScreenSupport
  228. // Does the installed version of QuickTime support the full-screen routines?
  229. //
  230. // Note: this is a pretty cheesy way of determining whether full-screen routines are available.
  231. //
  232. //////////
  233.  
  234. Boolean QTUtils_HasFullScreenSupport (void) 
  235. {
  236.     return(((QTUtils_GetQTVersion() >> 16) & 0xffff) >= kQTFullScreenMinVers);
  237. }
  238.  
  239.  
  240. //////////
  241. //
  242. // QTUtils_HasWiredSprites
  243. // Does the installed version of QuickTime support wired sprites?
  244. //
  245. // Note: this is a pretty cheesy way of determining whether wired sprites are available.
  246. //
  247. //////////
  248.  
  249. Boolean QTUtils_HasWiredSprites (void) 
  250. {
  251.     return(((QTUtils_GetQTVersion() >> 16) & 0xffff) >= kQTWiredSpritesMinVers);
  252. }
  253.  
  254.  
  255. //////////
  256. //
  257. // QTUtils_IsStreamedMovie
  258. // Is the specified movie a streamed movie?
  259. //
  260. //////////
  261.  
  262. Boolean QTUtils_IsStreamedMovie (Movie theMovie) 
  263. {
  264.     return(GetMovieIndTrackType(theMovie, 1, kQTSStreamMediaType, movieTrackMediaType | movieTrackEnabledOnly) != NULL);
  265. }
  266.  
  267.  
  268. //////////
  269. //
  270. // QTUtils_GetMovie
  271. // Open the specified movie file; if none is specified, query the user to select a file.
  272. //
  273. //////////
  274.  
  275. Movie QTUtils_GetMovie (FSSpec *theFSSpec, short *theRefNum, short *theResID)
  276. {
  277.     SFTypeList                myTypeList = {MovieFileType, 0, 0, 0};
  278.     StandardFileReply        myReply;
  279.     Movie                    myMovie = NULL;
  280.     OSErr                    myErr = noErr;
  281.  
  282.     // if we are provided with an FSSpec then use it; otherwise elicit a file from the user
  283.     if (theFSSpec == NULL || theFSSpec->vRefNum == 0) {    
  284.         StandardGetFilePreview(NULL, 1, myTypeList, &myReply);
  285.         if (!myReply.sfGood)
  286.             return(NULL);
  287.         
  288.         *theFSSpec = myReply.sfFile;
  289.     }
  290.  
  291.     // we should have now a usable FSSpec; just double check this before continuing
  292.     if (theFSSpec == NULL)
  293.         return NULL;
  294.     
  295.     // open the movie file
  296.     myErr = OpenMovieFile(theFSSpec, theRefNum, fsRdPerm);
  297.     if (myErr == noErr) {
  298.         Str255        myMovieName;
  299.         Boolean        wasChanged;
  300.         
  301.         *theResID = 0;                    // we want the first movie
  302.         
  303.         myErr = NewMovieFromFile(&myMovie, *theRefNum, theResID, myMovieName, newMovieActive, &wasChanged);
  304.         CloseMovieFile(*theRefNum);
  305.     }
  306.     
  307.     if (myErr != noErr)
  308.         return(NULL);
  309.     else
  310.         return(myMovie);
  311. }
  312.  
  313.  
  314. //////////
  315. //
  316. // QTUtils_SaveMovie
  317. // Save and flatten a movie resource into a file.
  318. //
  319. //////////
  320.  
  321. OSErr QTUtils_SaveMovie (Movie theMovie)
  322. {
  323.     StandardFileReply    mySFReply;
  324.     StringPtr             myPrompt = QTUtils_ConvertCToPascalString(kSavePrompt);
  325.     StringPtr             myFileName = QTUtils_ConvertCToPascalString(kSaveMovieFileName);
  326.     OSErr                myErr = noErr;
  327.     
  328.     if (theMovie == NULL)
  329.         return(invalidMovie);
  330.     
  331.     StandardPutFile(myPrompt, myFileName, &mySFReply); 
  332.     if (mySFReply.sfGood) {
  333.         FlattenMovieData(theMovie, flattenAddMovieToDataFork, &mySFReply.sfFile, FOUR_CHAR_CODE('TVOD'), smSystemScript, createMovieFileDeleteCurFile);
  334.         myErr = GetMoviesError();
  335.     }
  336.  
  337.     free(myPrompt);
  338.     free(myFileName);
  339.     
  340.     return(myErr);
  341. }
  342.  
  343.  
  344. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  345. //
  346. // Controller bar utilities.
  347. //
  348. // Use these functions to manipulate the controller bar, its buttons, and the help text displayed in it.
  349. //
  350. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  351.  
  352. //////////
  353. //
  354. // QTUtils_IsControllerBarVisible
  355. // Is the controller bar currently visible?
  356. //
  357. //////////
  358.  
  359. Boolean QTUtils_IsControllerBarVisible (MovieController theMC) 
  360. {
  361.     return((Boolean)MCGetVisible(theMC));
  362. }
  363.  
  364.  
  365. //////////
  366. //
  367. // QTUtils_GetControllerBarHeight
  368. // Return the height of the controller bar displayed by the movie controller.
  369. //
  370. // Note that MCGetControllerBoundsRect returns rectangle of bar and movie, if attached;
  371. // so we need to unattach the controller bar first.
  372. //
  373. //////////
  374.  
  375. short QTUtils_GetControllerBarHeight (MovieController theMC) 
  376. {
  377.     Boolean        wasAttached = false;
  378.     Rect        myRect;
  379.     short        myHeight = 0;
  380.     
  381.     // if the controller bar is attached, detach it (and remember we did so)
  382.     if (MCIsControllerAttached(theMC) == 1) {
  383.         wasAttached = true;
  384.         MCSetControllerAttached(theMC, false);
  385.     }
  386.     
  387.     // get the rectangle of the controller
  388.     MCGetControllerBoundsRect(theMC, &myRect);
  389.     myHeight = myRect.bottom - myRect.top;
  390.     
  391.     // now reattach the controller bar, if it was originally attached
  392.     if (wasAttached)
  393.         MCSetControllerAttached(theMC, true);
  394.     
  395.     return(myHeight);
  396. }
  397.  
  398.  
  399. //////////
  400. //
  401. // QTUtils_HideControllerBar
  402. // Hide the controller bar provided by the movie controller.
  403. //
  404. //////////
  405.  
  406. void QTUtils_HideControllerBar (MovieController theMC) 
  407. {
  408.     MCSetVisible(theMC, false);
  409. }
  410.  
  411.  
  412. //////////
  413. //
  414. // QTUtils_ShowControllerBar
  415. // Show the controller bar provided by the movie controller.
  416. //
  417. //////////
  418.  
  419. void QTUtils_ShowControllerBar (MovieController theMC) 
  420. {
  421.     MCSetVisible(theMC, true);
  422. }
  423.  
  424.  
  425. //////////
  426. //
  427. // QTUtils_ToggleControllerBar
  428. // Toggle the state of the controller bar provided by the movie controller.
  429. //
  430. //////////
  431.  
  432. void QTUtils_ToggleControllerBar (MovieController theMC) 
  433. {
  434.     if (QTUtils_IsControllerBarVisible(theMC))
  435.         QTUtils_HideControllerBar(theMC);
  436.     else
  437.         QTUtils_ShowControllerBar(theMC);
  438. }
  439.  
  440.  
  441. //////////
  442. //
  443. // QTUtils_HideControllerButton
  444. // Hide the specified button in the controller bar.
  445. //
  446. // Some explanation is probably useful here: the first thing to understand is that every VR movie has 
  447. // TWO sets of movie controller flags: (1) a set of "control flags" and (2) a set of "explicit flags".
  448. //
  449. // The control flags work as documented in IM: QuickTime Components (pp. 2-20f) and in VRPWQTVR2.0 (pp. 2-23f):
  450. // if a bit in the set of control flags is set (that is, equal to 1), then the associated action or property is
  451. // enabled. For instance, bit 17 (mcFlagQTVRSuppressZoomBtns) means to suppress the zoom buttons. So, if that
  452. // bit is set in a VR movie's control flags, the zoom buttons are NOT displayed. If that bit is clear, the zoom
  453. // buttons are displayed.
  454. //
  455. // However, the QuickTime VR movie controller sometimes suppresses buttons even when those buttons 
  456. // have not been explicitly suppressed in the control flags. For example, if a particular VR movie does not
  457. // contain a sound track, then the movie controller automatically suppresses the speaker/volume button. Likewise,
  458. // if a movie does contain a sound track, then the speaker/volume button is automatically displayed, again without
  459. // regard to the actual value of bit 17 in the control flags.
  460. //
  461. // This might not be what you'd like to happen. For instance, if your application is playing a sound that it
  462. // loaded from a sound resource, you might want the user to be able to adjust the sound's volume using the volume
  463. // control. To do that, you need a way to *force* the speaker/volume button to appear. For this reason, the
  464. // explicit flags were introduced.
  465. //
  466. // The explicit flags indicate which bits in the control flags are to be used explicitly (that is, taken at
  467. // face value). If a certain bit is set in a movie's explicit flags, then the corresponding bit in the control
  468. // flags is interpreted as the desired setting for the feature (and the movie controller will not attempt to
  469. // do anything "clever"). In other words, if bit 17 is set in a movie's explicit flags and bit 17 is clear in
  470. // that movie's control flags, then the zoom buttons are displayed. Similarly, if bit 2 is set in a movie's 
  471. // explicit flags and bit 2 is clear in that movie's control flags, then the speaker/volume button is displayed,
  472. // whether or not the movie contains a sound track.
  473. //
  474. // The final thing to understand: to get or set a bit in a movie's explicit flags, you must set the flag 
  475. // mcFlagQTVRExplicitFlagSet in your call to mcActionGetFlags or mcActionSetFlags. To get or set a bit in a 
  476. // movie's control flags, you must clear the flag mcFlagQTVRExplicitFlagSet in your call to mcActionGetFlags 
  477. // or mcActionSetFlags. Note that when you use the defined constants to set values in the explicit flags, the 
  478. // constant names might be confusing. For instance, setting the bit mcFlagSuppressSpeakerButton in a movie's
  479. // explicit flags doesn't cause the speaker to be suppressed; it just means: "use the actual value of the
  480. // mcFlagSuppressSpeakerButton bit in the control flags".
  481. //
  482. // Whew! Any questions? Okay, then now you'll understand how to hide or show a button in the controller bar:
  483. // set the appropriate explicit flag to 1 and set the corresponding control flag to the desired value. And
  484. // you'll understand how to let the movie controller do its "clever" work: clear the appropriate explicit flag.
  485. //
  486. //////////
  487.  
  488. void QTUtils_HideControllerButton (MovieController theMC, long theButton) 
  489. {
  490.     long    myControllerFlags;
  491.     
  492.     // get the current explicit flags and set the explicit flag for the specified button
  493.     myControllerFlags = mcFlagQTVRExplicitFlagSet;
  494.     MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  495.     MCDoAction(theMC, mcActionSetFlags, (void *)((myControllerFlags | theButton) | mcFlagQTVRExplicitFlagSet));
  496.     
  497.     // get the current control flags and set the suppress flag for the specified button
  498.     myControllerFlags = 0;
  499.     MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  500.     MCDoAction(theMC, mcActionSetFlags, (void *)((myControllerFlags | theButton) & ~mcFlagQTVRExplicitFlagSet));
  501. }
  502.  
  503.  
  504. //////////
  505. //
  506. // QTUtils_ShowControllerButton
  507. // Show the specified button in the controller bar.
  508. //
  509. //////////
  510.  
  511. void QTUtils_ShowControllerButton (MovieController theMC, long theButton) 
  512. {
  513.     long    myControllerFlags;
  514.     
  515.     // get the current explicit flags and set the explicit flag for the specified button
  516.     myControllerFlags = mcFlagQTVRExplicitFlagSet;
  517.     MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  518.     MCDoAction(theMC, mcActionSetFlags, (void *)((myControllerFlags | theButton) | mcFlagQTVRExplicitFlagSet));
  519.     
  520.     // get the current control flags and clear the suppress flag for the specified button
  521.     myControllerFlags = 0;
  522.     MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  523.     MCDoAction(theMC, mcActionSetFlags, (void *)(myControllerFlags & ~theButton & ~mcFlagQTVRExplicitFlagSet));
  524. }
  525.  
  526.  
  527. //////////
  528. //
  529. // QTUtils_ToggleControllerButton
  530. // Toggle the state of the specified button in the controller bar.
  531. //
  532. //////////
  533.  
  534. void QTUtils_ToggleControllerButton (MovieController theMC, long theButton) 
  535. {
  536.     long    myControllerFlags;
  537.     
  538.     // get the current control flags and toggle the suppress flag for the specified button
  539.     myControllerFlags = 0;
  540.     MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  541.     
  542.     if (myControllerFlags & theButton)                // if the button is currently suppressed...
  543.         QTUtils_ShowControllerButton(theMC, theButton);
  544.     else
  545.         QTUtils_HideControllerButton(theMC, theButton);
  546. }
  547.  
  548.  
  549. //////////
  550. //
  551. // QTUtils_ResetControllerButton
  552. // Remove any explicit setting of the specified button in the controller bar.
  553. // (This allows the QuickTime VR movie controller to be as clever as it knows how to be.)
  554. //
  555. //////////
  556.  
  557. void QTUtils_ResetControllerButton (MovieController theMC, long theButton) 
  558. {
  559.     long    myControllerFlags = mcFlagQTVRExplicitFlagSet;
  560.     
  561.     // get the current explicit flags and clear the explicit flag for the specified button
  562.     MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  563.     MCDoAction(theMC, mcActionSetFlags, (void *)((myControllerFlags | theButton) & ~mcFlagQTVRExplicitFlagSet));
  564. }
  565.  
  566.  
  567. //////////
  568. //
  569. // QTUtils_IsControllerButtonVisible
  570. // Is the specified button in the controller bar currently visible?
  571. //
  572. //////////
  573.  
  574. Boolean QTUtils_IsControllerButtonVisible (MovieController theMC, long theButton) 
  575. {
  576.     long        myControllerFlags;
  577.  
  578.     // get the current control flags
  579.     myControllerFlags = 0;
  580.     MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  581.  
  582.     // the speaker button requires some additional logic, because the QTVR movie controller treats it special;
  583.     // be advised that that controller's special behavior could change in the future,
  584.     // so you might need to tweak this code
  585.     if (theButton == mcFlagSuppressSpeakerButton) {
  586.         long    myExplicitFlags;
  587.         
  588.         // get the current explicit flags
  589.         myExplicitFlags = mcFlagQTVRExplicitFlagSet;
  590.         MCDoAction(theMC, mcActionGetFlags, &myExplicitFlags);
  591.     
  592.         // the speaker button is not showing if the movie has no sound track and the explicit flag is not set
  593.         if (!QTUtils_MovieHasSoundTrack(MCGetMovie(theMC)) && !(myExplicitFlags & theButton))
  594.             return(false);
  595.     }
  596.     
  597.     // examine the suppress flag for the specified button
  598.     if (myControllerFlags & theButton)                // if the button is currently suppressed...
  599.         return(false);
  600.     else
  601.         return(true);
  602. }
  603.  
  604.  
  605. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  606. //
  607. // Media utilities.
  608. //
  609. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  610.  
  611. //////////
  612. //
  613. // QTUtils_IsMediaTypeInMovie
  614. // Determine whether a specific media type is in a movie.
  615. // 
  616. //////////
  617.  
  618. Boolean QTUtils_IsMediaTypeInMovie (Movie theMovie, OSType theMediaType)
  619. {
  620.     return(GetMovieIndTrackType(theMovie, 1, theMediaType, movieTrackMediaType | movieTrackEnabledOnly) != NULL);
  621. }
  622.  
  623.  
  624. //////////
  625. //
  626. // QTUtils_MovieHasTimeCodeTrack
  627. // Determine whether a movie contains a timecode track.
  628. // 
  629. //////////
  630.  
  631. Boolean QTUtils_MovieHasTimeCodeTrack (Movie theMovie)
  632. {
  633.     return(GetMovieIndTrackType(theMovie, 1, TimeCodeMediaType, movieTrackMediaType) != NULL);
  634. }
  635.  
  636.  
  637. //////////
  638. //
  639. // QTUtils_MovieHasSoundTrack
  640. // Determine whether a movie contains a sound track.
  641. // 
  642. //////////
  643.  
  644. Boolean QTUtils_MovieHasSoundTrack (Movie theMovie)
  645. {
  646.     return(GetMovieIndTrackType(theMovie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly) != NULL);
  647. }
  648.  
  649.  
  650. //////////
  651. //
  652. // QTUtils_GetSoundMediaHandler
  653. // Return the sound media handler for a movie.
  654. // 
  655. //////////
  656.  
  657. MediaHandler QTUtils_GetSoundMediaHandler (Movie theMovie)
  658. {
  659.     Track        myTrack;
  660.     Media        myMedia;
  661.  
  662.     myTrack = GetMovieIndTrackType(theMovie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly);
  663.     if (myTrack != NULL) {
  664.         myMedia = GetTrackMedia(myTrack);
  665.         return(GetMediaHandler(myMedia));
  666.     } 
  667.         
  668.     return(NULL);
  669. }
  670.  
  671.  
  672. //////////
  673. //
  674. // QTUtils_PrintMoviePICT
  675. // Print the existing movie frame pict.
  676. // 
  677. // Note that in a real application we should put the PrStlDialog code into the Print Setup… menu
  678. // function. The reason it's inside this function is that we use this code for quick testing of printing.
  679. //
  680. //////////
  681.  
  682. OSErr QTUtils_PrintMoviePICT (Movie theMovie, short x, short y, long PICTUsed)
  683. {
  684.     PicHandle         myPictHandle = NULL;
  685.     THPrint            myTHPrint = NULL;
  686.     GrafPtr             mySavedPort;
  687.     TPPrPort        myPrintPort;
  688.     Boolean         myResult;
  689.     Boolean            isPrinting = false;
  690.     Rect            myPictRect;
  691.     OSErr            myErr = noErr;
  692.     
  693.     if (theMovie == NULL)
  694.         return(invalidMovie);
  695.     
  696.     GetPort(&mySavedPort);
  697.  
  698.     // get the PICT to be printed, either the poster pict or the current frame pict.
  699.     switch (PICTUsed) {
  700.         case kPrintFrame:
  701.             myPictHandle = GetMoviePict(theMovie, GetMovieTime(theMovie, 0L));
  702.             break;
  703.             
  704.         case kPrintPoster:
  705.             myPictHandle = GetMoviePosterPict(theMovie); 
  706.             break;
  707.  
  708.         default:
  709.             goto Closure;
  710.     }
  711.  
  712.     if (myPictHandle == NULL)
  713.         goto Closure;
  714.  
  715. #if TARGET_RT_LITTLE_ENDIAN
  716.     // change the fields of the Picture structure,
  717.     // if the target runtime environment uses little-endian format for integers
  718.     (**myPictHandle).picSize = EndianS16_BtoL((**myPictHandle).picSize);
  719.     
  720.     (**myPictHandle).picFrame.top = EndianS16_BtoL((**myPictHandle).picFrame.top);
  721.     (**myPictHandle).picFrame.left = EndianS16_BtoL((**myPictHandle).picFrame.left);
  722.     (**myPictHandle).picFrame.bottom = EndianS16_BtoL((**myPictHandle).picFrame.bottom);
  723.     (**myPictHandle).picFrame.right = EndianS16_BtoL((**myPictHandle).picFrame.right);
  724. #endif        
  725.  
  726.     // get the Print record
  727.     myTHPrint = (THPrint)NewHandleClear(sizeof(TPrint));
  728.     if (myTHPrint == NULL)
  729.         goto Closure;
  730.  
  731.     PrOpen();
  732.     isPrinting = true;
  733.     myErr = PrError();
  734.     if (myErr != noErr)
  735.         goto Closure;
  736.  
  737.     PrintDefault(myTHPrint);
  738.  
  739.     // move this to Print Setup… if you want to make this look really cool
  740.     myResult = PrStlDialog(myTHPrint);
  741.     if (!myResult)
  742.         goto Closure;
  743.     
  744.     myResult = PrJobDialog(myTHPrint);
  745.     if (!myResult)
  746.         goto Closure;
  747.     
  748.     myPrintPort = PrOpenDoc(myTHPrint, NULL, NULL);
  749.     PrOpenPage(myPrintPort, NULL);
  750.     myErr = PrError();
  751.     if (myErr != noErr)
  752.         goto Closure;
  753.     
  754.     // print at x,y position
  755.     myPictRect = (*myPictHandle)->picFrame;
  756.     MacOffsetRect(&myPictRect, (short)(x - myPictRect.left),  (short)(y - myPictRect.top));
  757.     
  758.     DrawPicture(myPictHandle, &myPictRect);
  759.  
  760.     // if you want to do additional drawing, do it here.
  761.     
  762.     PrClosePage(myPrintPort);
  763.     PrCloseDoc(myPrintPort);
  764.     myErr = PrError();
  765.     if (myErr != noErr)
  766.         goto Closure;
  767.     
  768.     if ((*myTHPrint)->prJob.bJDocLoop == bSpoolLoop)
  769.         PrPicFile(myTHPrint, NULL, NULL, NULL, NULL);
  770.     
  771.     // our closure handling
  772. Closure:
  773.     MacSetPort(mySavedPort);
  774.     
  775.     if (isPrinting)
  776.         PrClose();
  777.     if (myPictHandle)
  778.         KillPicture(myPictHandle);
  779.     if (myTHPrint)
  780.         DisposeHandle((Handle)myTHPrint);
  781.  
  782.     return(myErr);
  783. }
  784.  
  785.  
  786. //////////
  787. //
  788. // QTUtils_SelectAllMovie
  789. // Select the entire movie associated with the specified movie controller.
  790. // 
  791. //////////
  792.  
  793. OSErr QTUtils_SelectAllMovie (MovieController theMC)
  794. {
  795.     TimeRecord            myTimeRecord;
  796.     Movie                 myMovie = NULL;
  797.     ComponentResult        myErr = noErr;
  798.     
  799.     if (theMC == NULL)
  800.         return(paramErr);
  801.     
  802.     myMovie = MCGetMovie(theMC);
  803.     if (myMovie == NULL)
  804.         return(paramErr);
  805.     
  806.     myTimeRecord.value.hi = 0;
  807.     myTimeRecord.value.lo = 0;
  808.     myTimeRecord.base = 0;
  809.     myTimeRecord.scale = GetMovieTimeScale(myMovie);    
  810.     myErr = MCDoAction(theMC, mcActionSetSelectionBegin, &myTimeRecord);
  811.     if (myErr != noErr)
  812.         return((OSErr)myErr);
  813.     
  814.     myTimeRecord.value.hi = 0;
  815.     myTimeRecord.value.lo = GetMovieDuration(myMovie);    
  816.     myTimeRecord.base = 0;
  817.     myTimeRecord.scale = GetMovieTimeScale(myMovie);    
  818.     myErr = MCDoAction(theMC, mcActionSetSelectionDuration, &myTimeRecord);
  819.     
  820.     return((OSErr)myErr);
  821. }
  822.  
  823.  
  824. //////////
  825. //
  826. // QTUtils_MakeSampleDescription
  827. // Return a new image description with default and specified values.
  828. // 
  829. //////////
  830.  
  831. ImageDescriptionHandle QTUtils_MakeSampleDescription (long theEffectType, short theWidth, short theHeight)
  832. {
  833.     ImageDescriptionHandle        mySampleDesc = NULL;
  834.     OSErr                        myErr = noErr;
  835.  
  836.     // create a new sample description
  837.     mySampleDesc = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
  838.     if (mySampleDesc == NULL)
  839.         return(NULL);
  840.     
  841.     // fill in the fields of the sample description
  842.     (**mySampleDesc).idSize = sizeof(ImageDescription);
  843.     (**mySampleDesc).cType = theEffectType;
  844.     (**mySampleDesc).vendor = kAppleManufacturer;
  845.     (**mySampleDesc).temporalQuality = codecNormalQuality;
  846.     (**mySampleDesc).spatialQuality = codecNormalQuality;
  847.     (**mySampleDesc).width = theWidth;
  848.     (**mySampleDesc).height = theHeight;
  849.     (**mySampleDesc).hRes = 72L << 16;
  850.     (**mySampleDesc).vRes = 72L << 16;
  851.     (**mySampleDesc).dataSize = 0L;
  852.     (**mySampleDesc).frameCount = 1;
  853.     (**mySampleDesc).depth = 24;
  854.     (**mySampleDesc).clutID = -1;
  855.     
  856.     return(mySampleDesc);
  857. }
  858.  
  859.  
  860. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  861. //
  862. // User data utilities.
  863. //
  864. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  865.  
  866. #if CONTENT_RATING_AVAIL
  867. //////////
  868. //
  869. // QTUtils_GetContentRatingFromMovie
  870. // Get the content rating from a movie; return an error if it has none. In any case, return a meaningful
  871. // content rating.
  872. //
  873. //////////
  874.  
  875. OSErr QTUtils_GetContentRatingFromMovie (Movie theMovie, UInt16 *theRating, UInt32 *theReasons)
  876. {
  877.     UserData                    myUserData;
  878.     QTAltContentRatingRecord    myContentRec;
  879.     OSErr                        myErr = paramErr;
  880.  
  881.     *theRating = kQTContentTVYRating;
  882.     *theReasons = 0L;
  883.  
  884.     // make sure we've got a movie
  885.     if (theMovie == NULL)
  886.         return(myErr);
  887.         
  888.     // get the movie's user data list
  889.     myUserData = GetMovieUserData(theMovie);
  890.     if (myUserData != NULL) {
  891.         myErr = GetUserDataItem(myUserData, &myContentRec, sizeof(myContentRec), FOUR_CHAR_CODE('crat'), 0);
  892.         if (myErr == noErr) {
  893.             *theRating = EndianU16_BtoN(myContentRec.ratings);
  894.             *theReasons = EndianU32_BtoN(myContentRec.contentType);
  895.         }
  896.     }
  897.  
  898.     return(myErr);
  899. }
  900.  
  901.  
  902. //////////
  903. //
  904. // QTUtils_AddContentRatingToMovie
  905. // Add a content rating to a movie.
  906. //
  907. // A content rating is stored as a user data item that indicates both the general rating
  908. // (for example, TV-MA [mature audiences only]) and any additional information about the
  909. // content (for example, coarse language). Let's call this additional information the
  910. // "reasons" for the rating. Both the rating and the reasons are specified using constants
  911. // in the file MoviesFormat.h.
  912. //
  913. // This function adds the specified content rating to the movie's user data;
  914. // the updated user data is written to the movie file when the movie is next updated
  915. // (by calling UpdateMovieResource).
  916. // 
  917. //////////
  918.  
  919. OSErr QTUtils_AddContentRatingToMovie (Movie theMovie, UInt16 theRating, UInt32 theReasons)
  920. {
  921.     UserData                    myUserData;
  922.     QTAltContentRatingRecord    myContentRec;
  923.     OSErr                        myErr = noErr;
  924.  
  925.     // get the movie's user data list
  926.     myUserData = GetMovieUserData(theMovie);
  927.     if (myUserData == NULL)
  928.         return(paramErr);
  929.     
  930.     myContentRec.flags = 0;
  931.     myContentRec.contentType = EndianU32_NtoB(theReasons);
  932.     myContentRec.ratings = EndianU16_NtoB(theRating);
  933.     
  934.     // for simplicity, we assume that we want only one content rating in the movie;
  935.     // as a result, we won't worry about overwriting any existing item of that type
  936.  
  937.     // add the data to the movie's user data
  938.     myErr = SetUserDataItem(myUserData, &myContentRec, sizeof(myContentRec), FOUR_CHAR_CODE('crat'), 0);
  939.  
  940.     return(myErr);
  941. }
  942. #endif    // #if CONTENT_RATING_AVAIL
  943.  
  944.  
  945. //////////
  946. //
  947. // QTUtils_AddUserDataTextToMovie
  948. // Add a user data item, of the specified type, containing the specified text to a movie.
  949. //
  950. // This function adds the specified text to the movie's user data;
  951. // the updated user data is written to the movie file when the movie is next updated
  952. // (by calling UpdateMovieResource).
  953. // 
  954. //////////
  955.  
  956. OSErr QTUtils_AddUserDataTextToMovie (Movie theMovie, char *theText, OSType theType)
  957. {
  958.     UserData                    myUserData;
  959.     Handle                        myHandle = NULL;
  960.     short                        myIndex = 0;
  961.     long                        myLength = strlen(theText);
  962.     OSErr                        myErr = noErr;
  963.  
  964.     // get the movie's user data list
  965.     myUserData = GetMovieUserData(theMovie);
  966.     if (myUserData == NULL)
  967.         return(paramErr);
  968.     
  969.     // copy the specified text into a new handle
  970.     myHandle = NewHandleClear(myLength);
  971.     if (myHandle == NULL)
  972.         return(MemError());
  973.  
  974.     BlockMoveData(theText, *myHandle, myLength);
  975.  
  976.     // for simplicity, we assume that we want only one user data item of the specified type in the movie;
  977.     // as a result, we won't worry about overwriting any existing item of that type....
  978.     //
  979.     // if you need multiple user data items of a given type (for example, a copyright notice
  980.     // in several different languages), you would need to modify this code; this is left as an exercise
  981.     // for the reader....
  982.  
  983.     // add the data to the movie's user data
  984.     myErr = AddUserDataText(myUserData, myHandle, theType, myIndex + 1, smSystemScript);
  985.  
  986.     // clean up
  987.     DisposeHandle(myHandle);
  988.     return(myErr);
  989. }
  990.  
  991.  
  992. //////////
  993. //
  994. // QTUtils_AddCopyrightToMovie
  995. // Add a user data item containing the specified copyright text to a movie.
  996. //
  997. //////////
  998.  
  999. OSErr QTUtils_AddCopyrightToMovie (Movie theMovie, char *theText)
  1000. {
  1001.     return(QTUtils_AddUserDataTextToMovie(theMovie, theText, kUserDataTextCopyright));
  1002. }
  1003.  
  1004.  
  1005. //////////
  1006. //
  1007. // QTUtils_AddMovieNameToMovie
  1008. // Add a user data item containing the specified name to a movie.
  1009. //
  1010. //////////
  1011.  
  1012. OSErr QTUtils_AddMovieNameToMovie (Movie theMovie, char *theText)
  1013. {
  1014.     return(QTUtils_AddUserDataTextToMovie(theMovie, theText, kUserDataTextFullName));
  1015. }
  1016.  
  1017.  
  1018. //////////
  1019. //
  1020. // QTUtils_AddMovieInfoToMovie
  1021. // Add a user data item containing the specified information to a movie.
  1022. //
  1023. //////////
  1024.  
  1025. OSErr QTUtils_AddMovieInfoToMovie (Movie theMovie, char *theText)
  1026. {
  1027.     return(QTUtils_AddUserDataTextToMovie(theMovie, theText, kUserDataTextInformation));
  1028. }
  1029.  
  1030.  
  1031. //////////
  1032. //
  1033. // QTUtils_GetMovieFileLoopingInfo
  1034. // Get the looping state of a movie file.
  1035. //
  1036. // A movie file can have information about its looping state in a user data item of type 'LOOP'.
  1037. // If the movie doesn't contain an item of this type, then we'll assume that it isn't looping.
  1038. // If it does contain an item of this type, then the item data (a long integer) is 0 for normal
  1039. // looping and 1 for palindrome looping. Accordingly, this function returns the following values
  1040. // in the theLoopInfo parameter:
  1041. //
  1042. //        0 == normal looping
  1043. //        1 == palindrome looping
  1044. //        2 == no looping
  1045. //
  1046. //////////
  1047.  
  1048. OSErr QTUtils_GetMovieFileLoopingInfo (Movie theMovie, long *theLoopInfo)
  1049. {
  1050.     UserData        myUserData;
  1051.     long            myInfo = kNoLooping;
  1052.     OSErr            myErr = paramErr;
  1053.  
  1054.     // make sure we've got a movie
  1055.     if (theMovie == NULL)
  1056.         goto bail;
  1057.         
  1058.     // get the movie's user data list
  1059.     myUserData = GetMovieUserData(theMovie);
  1060.     if (myUserData != NULL)
  1061.         myErr = GetUserDataItem(myUserData, &myInfo, sizeof(myInfo), FOUR_CHAR_CODE('LOOP'), 0);
  1062.  
  1063. bail:
  1064.     *theLoopInfo = myInfo;
  1065.  
  1066.     return(myErr);
  1067. }
  1068.  
  1069.  
  1070. //////////
  1071. //
  1072. // QTUtils_SetMovieFileLoopingInfo
  1073. // Set the looping state for a movie file.
  1074. //
  1075. //////////
  1076.  
  1077. OSErr QTUtils_SetMovieFileLoopingInfo (Movie theMovie, long theLoopInfo)
  1078. {
  1079.     UserData        myUserData;
  1080.     short            myCount = 0;
  1081.     OSErr            myErr = paramErr;
  1082.  
  1083.     // get the movie's user data
  1084.     myUserData = GetMovieUserData(theMovie);
  1085.     if (myUserData == NULL)
  1086.         goto bail;
  1087.  
  1088.     // we want to end up with at most one user data item of type 'LOOP',
  1089.     // so let's remove any existing ones
  1090.     myCount = CountUserDataType(myUserData, FOUR_CHAR_CODE('LOOP'));
  1091.     while (myCount--)
  1092.         RemoveUserData(myUserData, FOUR_CHAR_CODE('LOOP'), 1);
  1093.  
  1094.     switch (theLoopInfo) {
  1095.         case kNormalLooping:
  1096.         case kPalindromeLooping:
  1097.             myErr = SetUserDataItem(myUserData, &theLoopInfo, sizeof(long), FOUR_CHAR_CODE('LOOP'), 0);
  1098.             break;
  1099.  
  1100.         case kNoLooping:
  1101.         default:
  1102.             myErr = noErr;
  1103.             break;
  1104.     }
  1105.  
  1106. bail:
  1107.     return(myErr);
  1108. }
  1109.  
  1110.  
  1111. //////////
  1112. //
  1113. // QTUtils_SetLoopingStateFromFile
  1114. // Set the looping state for a movie based on the looping information in the movie file.
  1115. //
  1116. //////////
  1117.  
  1118. OSErr QTUtils_SetLoopingStateFromFile (Movie theMovie, MovieController theMC)
  1119. {
  1120.     long             myLoopInfo;
  1121.     OSErr            myErr = noErr;
  1122.  
  1123.     myErr = QTUtils_GetMovieFileLoopingInfo(theMovie, &myLoopInfo);
  1124.     switch (myLoopInfo) {
  1125.  
  1126.         case kNormalLooping:
  1127.             MCDoAction(theMC, mcActionSetLooping, (void *)true);
  1128.             MCDoAction(theMC, mcActionSetLoopIsPalindrome, (void *)false);
  1129.             break;
  1130.  
  1131.         case kPalindromeLooping:
  1132.             MCDoAction(theMC, mcActionSetLooping, (void *)true);
  1133.             MCDoAction(theMC, mcActionSetLoopIsPalindrome, (void *)true);
  1134.             break;
  1135.  
  1136.         case kNoLooping:
  1137.         default:
  1138.             MCDoAction(theMC, mcActionSetLooping, (void *)false);
  1139.             MCDoAction(theMC, mcActionSetLoopIsPalindrome, (void *)false);
  1140.             break;
  1141.     }
  1142.  
  1143.     return(myErr);
  1144. }
  1145.  
  1146.  
  1147. //////////
  1148. //
  1149. // QTUtils_MakeMovieLoop
  1150. // Set the specified movie to loop.
  1151. //
  1152. // Based on the function MakeMovieLoop by Kevin Marks.
  1153. //
  1154. //////////
  1155.  
  1156. OSErr QTUtils_MakeMovieLoop (Movie theMovie, Boolean isPalindrome)
  1157. {
  1158.     TimeBase        myTimeBase = NULL;
  1159.     long             myFlags = 0L;
  1160.     OSErr            myErr = paramErr;
  1161.  
  1162.     // make sure we've got a movie
  1163.     if (theMovie == NULL)
  1164.         goto bail;
  1165.     
  1166.     myErr = noErr;
  1167.         
  1168.     // set the movie's play hints to enhance looping performance
  1169.     SetMoviePlayHints(theMovie, hintsLoop, hintsLoop);
  1170.     
  1171.     // set the looping flag of the movie's time base
  1172.     myTimeBase = GetMovieTimeBase(theMovie);
  1173.     myFlags = GetTimeBaseFlags(myTimeBase);
  1174.     myFlags |= loopTimeBase;
  1175.     
  1176.     // set or clear the palindrome flag, depending on the specified setting
  1177.     if (isPalindrome)
  1178.         myFlags |= palindromeLoopTimeBase;
  1179.     else
  1180.         myFlags &= ~palindromeLoopTimeBase;
  1181.         
  1182.     SetTimeBaseFlags(myTimeBase, myFlags);
  1183.  
  1184. bail:
  1185.     return(myErr);
  1186. }
  1187.  
  1188.  
  1189. //////////
  1190. //
  1191. // QTUtils_GetTrackName
  1192. // Get the name of the specified movie track.
  1193. //
  1194. // This routine is modelled on the one contained in Dispatch 2 from the Ice Floe;
  1195. // I've modified it to return a C string instead of a Pascal string.
  1196. //
  1197. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  1198. //
  1199. //////////
  1200.  
  1201. char *QTUtils_GetTrackName (Track theTrack)
  1202. {
  1203.     UserData            myUserData;
  1204.     char                *myString = NULL;
  1205.      OSErr                myErr = noErr;
  1206.  
  1207.     // make sure we've got a track
  1208.     if (theTrack == NULL)
  1209.         return(NULL);
  1210.         
  1211.     // a track's name (if it has one) is stored in the track's user data
  1212.     myUserData = GetTrackUserData(theTrack);
  1213.     if (myUserData != NULL) {
  1214.         Handle            myHandle = NewHandle(0);
  1215.  
  1216.         // get the user data item of type kUserDataName;
  1217.         // the handle we pass to GetUserData is resized to contain the track name
  1218.         myErr = GetUserData(myUserData, myHandle, kUserDataName, 1);
  1219.         if (myErr == noErr) {
  1220.             long        myLength = GetHandleSize(myHandle);
  1221.  
  1222.             if (myLength > 0) {
  1223.                 myString = malloc(myLength + 1);
  1224.                 if (myString != NULL) {
  1225.                     memcpy(myString, *myHandle, myLength);
  1226.                     myString[myLength] = '\0';
  1227.                 }
  1228.             }            
  1229.         }    
  1230.  
  1231.         DisposeHandle(myHandle);
  1232.     }
  1233.  
  1234.     return(myString);
  1235. }
  1236.  
  1237.  
  1238. //////////
  1239. //
  1240. // QTUtils_SetTrackName
  1241. // Set the name of the specified movie track.
  1242. //
  1243. // This function adds the specified text to the track's user data;
  1244. // the updated user data is written to the movie file when the movie is next updated
  1245. // (by calling UpdateMovieResource).
  1246. //
  1247. //////////
  1248.  
  1249. OSErr QTUtils_SetTrackName (Track theTrack, char *theText)
  1250. {
  1251.     UserData            myUserData;
  1252.     OSErr                myErr = noErr;
  1253.  
  1254.     // make sure we've got a track and a name
  1255.     if ((theTrack == NULL) || (theText == NULL))
  1256.         return(paramErr);
  1257.         
  1258.     // get the track's user data list
  1259.     myUserData = GetTrackUserData(theTrack);
  1260.     if (myUserData == NULL)
  1261.         return(paramErr);
  1262.     
  1263.     // remove any existing track name
  1264.     while (RemoveUserData(myUserData, kUserDataName, 1) == noErr)
  1265.         ;
  1266.  
  1267.     myErr = SetUserDataItem(myUserData, theText, strlen(theText), kUserDataName, 0);
  1268.  
  1269.     return(myErr);
  1270. }
  1271.  
  1272.  
  1273. //////////
  1274. //
  1275. // QTUtils_MakeTrackNameByType
  1276. // Create a (unique) name for the specified track, based on the track's type.
  1277. //
  1278. // Given a movie track, this routine constructs a name for that track based on
  1279. // the media type of that track. For instance, if the track is a sound track,
  1280. // this routine returns the name "Sound". However, if there is more than one
  1281. // track of that media type, then this routine numbers the track names. So, if
  1282. // there are two sound tracks, this routine names them "Sound 1" and "Sound 2".
  1283. //
  1284. // This routine is modelled on the one contained in Dispatch 2 from the Ice Floe;
  1285. // I've modified it to return a C string instead of a Pascal string.
  1286. //
  1287. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  1288. //
  1289. //////////
  1290.  
  1291. char *QTUtils_MakeTrackNameByType (Track theTrack)
  1292. {
  1293.     Media                myMedia;
  1294.     char                *myString = NULL;
  1295.      OSErr                myErr = noErr;
  1296.  
  1297.     // make sure we've got a track
  1298.     if (theTrack == NULL)
  1299.         return(NULL);
  1300.     
  1301.     myMedia = GetTrackMedia(theTrack);
  1302.     if (myMedia != NULL) {
  1303.         MediaHandler    myMediaHandler = GetMediaHandler(myMedia);
  1304.         OSType            myMediaType;
  1305.         Str255            myName;
  1306.  
  1307.         // get the media type of the track
  1308.         GetMediaHandlerDescription(myMedia, &myMediaType, NULL, NULL);
  1309.         
  1310.         // get the text of the media type
  1311.         myErr = MediaGetName(myMediaHandler, myName, 0, NULL);
  1312.         if (myErr == noErr) {
  1313.             
  1314.             // determine whether there's more than one track with this media type
  1315.             if (GetMovieIndTrackType(GetTrackMovie(theTrack), 2, myMediaType, movieTrackMediaType) != NULL) {
  1316.  
  1317.                 // add an index number to the track type string we constructed above
  1318.                 long    myIndex = 1;
  1319.                 Str255    myNumString;
  1320.  
  1321.                 while (GetMovieIndTrackType(GetTrackMovie(theTrack), myIndex, myMediaType, movieTrackMediaType) != theTrack)
  1322.                    myIndex++;
  1323.  
  1324.                 NumToString(myIndex, myNumString);
  1325.                 myName[++myName[0]] = ' ';
  1326.                 BlockMoveData(&myNumString[1], &myName[myName[0] + 1], myNumString[0]);
  1327.                 myName[0] += myNumString[0];
  1328.             }
  1329.  
  1330.             // now copy the string data from the Pascal string to a C string
  1331.             if (myName[0] > 0) {
  1332.                 myString = malloc(myName[0] + 1);
  1333.                 if (myString != NULL) {
  1334.                     memcpy(myString, &myName[1], myName[0]);
  1335.                     myString[myName[0]] = '\0';
  1336.                 }
  1337.             }            
  1338.         }
  1339.     }
  1340.  
  1341.     return(myString);
  1342. }
  1343.  
  1344.  
  1345. //////////
  1346. //
  1347. // QTUtils_IsImageFile
  1348. // Is the specified file an image file?
  1349. //
  1350. //////////
  1351.  
  1352. Boolean QTUtils_IsImageFile (FSSpec *theFSSpec)
  1353. {    
  1354.     Boolean                        isImageFile = false;
  1355.     GraphicsImportComponent        myImporter = NULL;
  1356.  
  1357.     GetGraphicsImporterForFile(theFSSpec, &myImporter);
  1358.     if (myImporter != NULL) {
  1359.         // this file is a still image
  1360.         isImageFile = true;
  1361.         CloseComponent(myImporter);
  1362.     }
  1363.  
  1364.     return(isImageFile);
  1365. }
  1366.  
  1367.  
  1368. //////////
  1369. //
  1370. // QTUtils_IsMovieFile
  1371. // Is the specified file a file that can be opened by QuickTime as a movie?
  1372. //
  1373. // This apparently isn't working correctly: GMIFDR always returns -2003 (cantFindHandler)
  1374. //
  1375. //////////
  1376.  
  1377. Boolean QTUtils_IsMovieFile (FSSpec *theFSSpec)
  1378. {    
  1379.     Boolean                        isMovieFile = false;
  1380.     AliasHandle                    myAlias = NULL;
  1381.     Component                    myImporter = NULL;
  1382.     OSErr                        myErr = noErr;
  1383.  
  1384.     NewAliasMinimal(theFSSpec, &myAlias);
  1385.     GetMovieImporterForDataRef(rAliasType, (Handle)myAlias, kGetMovieImporterDontConsiderGraphicsImporters, &myImporter);
  1386.  
  1387.     DisposeHandle((Handle)myAlias);
  1388.     if (myImporter != NULL)        // this file is a movie file
  1389.         isMovieFile = true;
  1390.  
  1391.     return(isMovieFile);
  1392. }
  1393.  
  1394.  
  1395. //////////
  1396. //
  1397. // QTUtils_ConvertFloatToBigEndian
  1398. // Convert the specified floating-point number to big-endian format.
  1399. //
  1400. //////////
  1401.  
  1402. void QTUtils_ConvertFloatToBigEndian (float *theFloat)
  1403. {
  1404.     unsigned long        *myLongPtr;
  1405.     
  1406.     myLongPtr = (unsigned long *)theFloat;
  1407.     *myLongPtr = EndianU32_NtoB(*myLongPtr);
  1408. }
  1409.  
  1410.  
  1411. //////////
  1412. //
  1413. // QTUtils_ConvertCToPascalString
  1414. // Convert a C string into a Pascal string.
  1415. //
  1416. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  1417. //
  1418. //////////
  1419.  
  1420. StringPtr QTUtils_ConvertCToPascalString (char *theString)
  1421. {
  1422.     StringPtr    myString = malloc(strlen(theString) + 1);
  1423.     short        myIndex = 0;
  1424.  
  1425.     while (theString[myIndex] != '\0') {
  1426.         myString[myIndex + 1] = theString[myIndex];
  1427.         myIndex++;
  1428.     }
  1429.     
  1430.     myString[0] = (unsigned char)myIndex;
  1431.     
  1432.     return(myString);
  1433. }
  1434.  
  1435.  
  1436. //////////
  1437. //
  1438. // QTUtils_ConvertPascalToCString
  1439. // Convert a Pascal string into a C string.
  1440. //
  1441. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  1442. //
  1443. //////////
  1444.  
  1445. char *QTUtils_ConvertPascalToCString (StringPtr theString)
  1446. {
  1447.     char         *myString = malloc(theString[0] + 1);
  1448.     short        myIndex = 0;
  1449.  
  1450.     for (myIndex = 0; myIndex < theString[0]; myIndex++)
  1451.         myString[myIndex] = theString[myIndex + 1];
  1452.     
  1453.     myString[theString[0]] = '\0';
  1454.     
  1455.     return(myString);
  1456. }
  1457.  
  1458.  
  1459. //////////
  1460. //
  1461. // QTUtils_DeleteAllReferencesToTrack
  1462. // Delete all existing track references to the specified track.
  1463. //
  1464. //////////
  1465.  
  1466. OSErr QTUtils_DeleteAllReferencesToTrack (Track theTrack)
  1467. {
  1468.     Movie                myMovie = NULL;
  1469.     Track                myTrack = NULL;
  1470.     long                myTrackCount = 0L;
  1471.     long                myTrRefCount = 0L;
  1472.     long                myTrackIndex;
  1473.     long                myTrRefIndex;
  1474.     OSErr                myErr = noErr;
  1475.  
  1476.     myMovie = GetTrackMovie(theTrack);
  1477.     if (myMovie == NULL)
  1478.         return(paramErr);
  1479.  
  1480.     // iterate thru all the tracks in the movie (that are different from the specified track)
  1481.     myTrackCount = GetMovieTrackCount(myMovie);
  1482.     for (myTrackIndex = 1; myTrackIndex <= myTrackCount; myTrackIndex++) {
  1483.         myTrack = GetMovieIndTrack(myMovie, myTrackIndex);
  1484.         if ((myTrack != NULL) && (myTrack != theTrack)) {
  1485.             OSType        myType = 0L;
  1486.     
  1487.             // iterate thru all track reference types contained in the current track
  1488.             myType = GetNextTrackReferenceType(myTrack, myType);
  1489.             while (myType != 0L) {
  1490.  
  1491.                 // iterate thru all track references of the current type;
  1492.                 // note that we count down to 1, since DeleteTrackReference will cause
  1493.                 // any higher-indexed track references to be renumbered
  1494.                 myTrRefCount = GetTrackReferenceCount(myTrack, myType);
  1495.                 for (myTrRefIndex = myTrRefCount; myTrRefIndex >= 1; myTrRefIndex--) {
  1496.                     Track    myRefTrack = NULL;
  1497.  
  1498.                     myRefTrack = GetTrackReference(myTrack, myType, myTrRefIndex);
  1499.                     if (myRefTrack == theTrack)
  1500.                         myErr = DeleteTrackReference(myTrack, myType, myTrRefIndex);
  1501.                 }
  1502.  
  1503.                 myType = GetNextTrackReferenceType(myTrack, myType);
  1504.             }
  1505.         }
  1506.     }
  1507.  
  1508.     return(myErr);
  1509. }
  1510.  
  1511.  
  1512. //////////
  1513. //
  1514. // QTUtils_GetFrameDuration
  1515. // Get the duration of the first sample frame in the specified movie track.
  1516. //
  1517. //////////
  1518.  
  1519. TimeValue QTUtils_GetFrameDuration (Track theTrack)
  1520. {    
  1521.     TimeValue    mySampleDuration;
  1522.     OSErr        myErr = noErr;
  1523.  
  1524.     myErr = GetMediaSample(    GetTrackMedia(theTrack),
  1525.                             NULL,         // don't return sample data
  1526.                             0,
  1527.                             NULL,        // don't return number of bytes of sample data returned
  1528.                             0,
  1529.                             NULL,
  1530.                             &mySampleDuration,
  1531.                             NULL,        // don't return sample description
  1532.                             NULL,        // don't return sample description index
  1533.                             0,            // no max number of samples
  1534.                             NULL,        // don't return number of samples returned
  1535.                             NULL);        // don't return sample flags
  1536.  
  1537.     // make sure we return a legitimate value even if GetMediaSample encounters an error
  1538.     if (myErr != noErr)
  1539.         mySampleDuration = 0;
  1540.  
  1541.     return(mySampleDuration);
  1542. }
  1543.  
  1544.  
  1545. //////////
  1546. //
  1547. // QTUtils_GetFrameCount
  1548. // Get the number of frames in the specified movie track. We return the value -1 if
  1549. // an error occurs and we cannot determine the number of frames in the track.
  1550. //
  1551. // Based (loosely) on frame-counting code in ConvertToMovie Jr.c.
  1552. // 
  1553. // We count the frames in the track by stepping through all of its interesting times
  1554. // (the places where the track displays a new sample).
  1555. //
  1556. //////////
  1557.  
  1558. long QTUtils_GetFrameCount (Track theTrack)
  1559. {    
  1560.     long        myCount = -1;
  1561.     short        myFlags;
  1562.     TimeValue    myTime = 0;
  1563.     
  1564.     if (theTrack == NULL)
  1565.         goto bail;
  1566.         
  1567.     // we want to begin with the first frame (sample) in the track
  1568.     myFlags = nextTimeMediaSample + nextTimeEdgeOK;
  1569.  
  1570.     while (myTime >= 0) {
  1571.         myCount++;
  1572.         
  1573.         // look for the next frame in the track; when there are no more frames,
  1574.         // myTime is set to -1, so we'll exit the while loop
  1575.         GetTrackNextInterestingTime(theTrack, myFlags, myTime, fixed1, &myTime, NULL);
  1576.         
  1577.         // after the first interesting time, don't include the time we're currently at
  1578.         myFlags = nextTimeStep;
  1579.     }
  1580.  
  1581. bail:
  1582.     return(myCount);
  1583. }
  1584.  
  1585.  
  1586. //////////
  1587. //
  1588. // QTUtils_GetMaxWindowDepth
  1589. // Get the deepest pixel type and size of the screen area intersected by a specified window.
  1590. //
  1591. //////////
  1592.  
  1593. void QTUtils_GetMaxWindowDepth (CWindowPtr theWindow, short *thePixelType, short *thePixelSize)
  1594. {
  1595.     Rect            myRect;
  1596.     Point            myPoint = {0, 0};
  1597.     
  1598.     // initialize returned values 
  1599.     *thePixelType = k1MonochromePixelFormat;
  1600.     *thePixelSize = 0;
  1601.  
  1602.     if (theWindow == NULL)
  1603.         return;
  1604.  
  1605.     myRect = theWindow->portRect;
  1606.     
  1607.     // assume the window is the current port
  1608.     LocalToGlobal(&myPoint);
  1609.  
  1610.     // offset the rectangle to global coordinates
  1611.     MacOffsetRect(&myRect, myPoint.h, myPoint.v);
  1612.     
  1613.     // get the max data for the global rectangle
  1614.     QTUtils_GetMaxScreenDepth(&myRect, thePixelType, thePixelSize);
  1615. }
  1616.  
  1617.  
  1618. //////////
  1619. //
  1620. // QTUtils_GetMaxScreenDepth
  1621. // Get the deepest pixel type and size of the screen area intersected by a specified rectangle.
  1622. //
  1623. //////////
  1624.  
  1625. void QTUtils_GetMaxScreenDepth (Rect *theGlobalRect, short *thePixelType, short *thePixelSize)
  1626. {
  1627.     GDHandle        myGDevice = NULL;
  1628.     PixMapHandle    myPixMap = NULL;
  1629.  
  1630.     myGDevice = GetMaxDevice(theGlobalRect);    // get the max device
  1631.     if (myGDevice != NULL) {
  1632.         // get the pixmap for the max device
  1633.         myPixMap = (**myGDevice).gdPMap;
  1634.         if (myPixMap != NULL) {
  1635.             // extract the interesting info from the pixmap of the device
  1636.             *thePixelType = (**myPixMap).pixelType;
  1637.             *thePixelSize = (**myPixMap).pixelSize;
  1638.         }
  1639.     }
  1640. }
  1641.  
  1642.  
  1643. //////////
  1644. //
  1645. // QTUtils_GetUsersConnectionSpeed
  1646. // Return the connection speed selected by the user in the QuickTime Settings control panel;
  1647. // return 0 if the user's QuickTime preferences cannot be read.
  1648. //
  1649. // Based on code in Ice Floe Dispatch 17 by Mike Dodd.
  1650. //
  1651. //////////
  1652.  
  1653. long QTUtils_GetUsersConnectionSpeed (void)
  1654. {
  1655.     QTAtomContainer                    myPrefsContainer = NULL;
  1656.     QTAtom                            myPrefsAtom = 0;
  1657.     ConnectionSpeedPrefsRecord        myPrefsRec;
  1658.     long                            myDataSize = 0L;
  1659.     long                            mySpeed = 0L;
  1660.     Ptr                                myAtomData = NULL;
  1661.     OSErr                            myErr = noErr;
  1662.  
  1663.     // you can retrieve the user's QuickTime preferences by calling GetQuickTimePreference;
  1664.     // the first parameter indicates the type of preference you want information about, and
  1665.     // the second parameter is an atom container that contains the returned preference data 
  1666.     myErr = GetQuickTimePreference(ConnectionSpeedPrefsType, &myPrefsContainer);
  1667.     if (myErr == noErr) {
  1668.             
  1669.         // find the atom of the desired type
  1670.         myPrefsAtom = QTFindChildByID(myPrefsContainer, kParentAtomIsContainer, ConnectionSpeedPrefsType, 1, NULL);
  1671.         if (myPrefsAtom == 0) {
  1672.             // we did not find any such atom in the returned atom container, so we'll
  1673.             // return a default connection speed setting of 28.8K bytes per second
  1674.             mySpeed = kDataRate288ModemRate;
  1675.         } else {
  1676.             // we found the desired atom in the returned atom container;
  1677.             // read the data contained in that atom and verify that the data is of the
  1678.             // size we are expecting
  1679.             QTGetAtomDataPtr(myPrefsContainer, myPrefsAtom, &myDataSize, &myAtomData);
  1680.             
  1681.             if (myDataSize != sizeof(ConnectionSpeedPrefsRecord)) {
  1682.                 // the data in the atom isn't the right size, so it must be corrupt;
  1683.                 // return a default connection speed setting of 28.8K bytes per second
  1684.                 mySpeed = kDataRate288ModemRate;
  1685.             } else {
  1686.                 // everything is fine: read the connection speed
  1687.                 
  1688.                 // NOTE: the data in this atom is native-endian, so we do not need to
  1689.                 // perform any endian-swapping when extracting the speed from the atom.
  1690.                 // (This is an exception to the rule that data in atom containers is
  1691.                 // always big-endian.)
  1692.                 myPrefsRec = *(ConnectionSpeedPrefsRecord *)myAtomData;
  1693.                 mySpeed = myPrefsRec.connectionSpeed;
  1694.             }
  1695.         }
  1696.  
  1697.         QTDisposeAtomContainer(myPrefsContainer);
  1698.     }
  1699.     
  1700.     return(mySpeed);
  1701. }
  1702.  
  1703.  
  1704. //////////
  1705. //
  1706. // QTUtils_SetUsersConnectionSpeed
  1707. // Set the connection speed in the QuickTime Settings control panel to the specified value.
  1708. //
  1709. // NOTE: In general, you should let the user decide the connection speed (using the QuickTime
  1710. // Settings control panel). In some cases, however, you might need to do this programmatically.
  1711. // Also, you should in general use values for theSpeed that are enumerated in the header file
  1712. // MoviesFormat.h.
  1713. //
  1714. // Based on code in Ice Floe Dispatch 17 by Mike Dodd.
  1715. //
  1716. //////////
  1717.  
  1718. OSErr QTUtils_SetUsersConnectionSpeed (long theSpeed)
  1719. {
  1720.     QTAtomContainer                    myPrefsContainer = NULL;
  1721.     QTAtom                            myPrefsAtom = 0;
  1722.     ConnectionSpeedPrefsRecord        myPrefsRec;
  1723.     OSErr                            myErr = noErr;
  1724.  
  1725.     myErr = QTNewAtomContainer(&myPrefsContainer);
  1726.     if (myErr == noErr) {
  1727.         // NOTE: the data in this atom is native-endian, so we do not need to
  1728.         // perform any endian-swapping when inserting the speed into the atom.
  1729.         // (This is an exception to the rule that data in atom containers is
  1730.         // always big-endian.)
  1731.         myPrefsRec.connectionSpeed = theSpeed;
  1732.         
  1733.         myErr = QTInsertChild(myPrefsContainer, kParentAtomIsContainer, ConnectionSpeedPrefsType, 1, 0, sizeof(ConnectionSpeedPrefsRecord), &myPrefsRec, &myPrefsAtom);
  1734.         if (myErr == noErr)
  1735.             myErr = SetQuickTimePreference(ConnectionSpeedPrefsType, myPrefsContainer);
  1736.             
  1737.         QTDisposeAtomContainer(myPrefsContainer);
  1738.     }
  1739.  
  1740.     return(myErr);
  1741. }
  1742.  
  1743.  
  1744. #if CONTENT_RATING_AVAIL
  1745. //////////
  1746. //
  1747. // QTUtils_GetUsersContentRating
  1748. // Return, through the function's parameters, the content rating and acceptable content types
  1749. // selected by the user in the QuickTime Settings control panel; return an error if the user's
  1750. // QuickTime preferences cannot be read.
  1751. //
  1752. // Based on QTUtils_GetUsersConnectionSpeed.
  1753. //
  1754. //////////
  1755.  
  1756. OSErr QTUtils_GetUsersContentRating (UInt32 *theType, UInt16 *theRating)
  1757. {
  1758.     QTAtomContainer                    myPrefsContainer = NULL;
  1759.     QTAtom                            myPrefsAtom = 0;
  1760.     ContentRatingPrefsRecord        myContentRec;
  1761.     long                            myDataSize = 0L;
  1762.     Ptr                                myAtomData = NULL;
  1763.     OSErr                            myErr = noErr;
  1764.  
  1765.     // you can retrieve the user's QuickTime preferences by calling GetQuickTimePreference;
  1766.     // the first parameter indicates the type of preference you want information about, and
  1767.     // the second parameter is an atom container that contains the returned preference data 
  1768.     myErr = GetQuickTimePreference(kContentRatingPrefsType, &myPrefsContainer);
  1769.     if (myErr == noErr) {
  1770.             
  1771.         // find the atom of the desired type
  1772.         myPrefsAtom = QTFindChildByID(myPrefsContainer, kParentAtomIsContainer, kContentRatingPrefsType, 1, NULL);
  1773.         if (myPrefsAtom == 0) {
  1774.             // we did not find any such atom in the returned atom container, so we'll
  1775.             // return default settings
  1776.             *theType = 0L;
  1777.             *theRating = kQTContentTVYRating;
  1778.         } else {
  1779.             // we found the desired atom in the returned atom container;
  1780.             // read the data contained in that atom and verify that the data is of the
  1781.             // size we are expecting
  1782.             myErr = QTGetAtomDataPtr(myPrefsContainer, myPrefsAtom, &myDataSize, &myAtomData);
  1783.             
  1784.             if (myDataSize != sizeof(ContentRatingPrefsRecord)) {
  1785.                 // the data in the atom isn't the right size, so it must be corrupt;
  1786.                 // return default settings
  1787.                 *theType = 0L;
  1788.                 *theRating = kQTContentTVYRating;
  1789.             } else {
  1790.                 // everything is fine: read the content information
  1791.                 
  1792.                 // NOTE: the data in this atom is native-endian, so we do not need to
  1793.                 // perform any endian-swapping when extracting the data from the atom.
  1794.                 // (This is an exception to the rule that data in atom containers is
  1795.                 // always big-endian.)
  1796.                 
  1797.                 // WARNING: the format of the data in a content rating atom is, to my
  1798.                 // knowledge, currently undocumented; the following method of extracting
  1799.                 // that info is based on empirical investigation.
  1800.                 myContentRec = *(ContentRatingPrefsRecord *)myAtomData;
  1801.                 *theType = (UInt32)(~(myContentRec.fContentTypes) & 0x00ff);
  1802.                 *theRating = myContentRec.fContentRating;
  1803.             }
  1804.         }
  1805.  
  1806.         QTDisposeAtomContainer(myPrefsContainer);
  1807.     }
  1808.     
  1809.     return(myErr);
  1810. }
  1811. #endif    // #if CONTENT_RATING_AVAIL
  1812.  
  1813.  
  1814. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1815. //
  1816. // Controller utilities.
  1817. //
  1818. // Use these functions to manipulate movie controllers.
  1819. //
  1820. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1821.  
  1822. //////////
  1823. //
  1824. // QTUtils_GetControllerType
  1825. // Get the controller type of the specified movie.
  1826. //
  1827. //////////
  1828.  
  1829. OSType QTUtils_GetControllerType (Movie theMovie) 
  1830. {
  1831.     UserData        myUserData;
  1832.     OSType            myType = kQTVRUnknownType;
  1833.     
  1834.     // make sure we've got a movie
  1835.     if (theMovie == NULL)
  1836.         return(myType);
  1837.         
  1838.     myUserData = GetMovieUserData(theMovie);
  1839.     if (myUserData != NULL)
  1840.         GetUserDataItem(myUserData, &myType, sizeof(myType), kUserDataMovieControllerType, 0);
  1841.     
  1842.     return(EndianU32_BtoN(myType));
  1843. }
  1844.  
  1845.  
  1846. //////////
  1847. //
  1848. // QTUtils_SetControllerType
  1849. // Set the controller type of the specified movie.
  1850. //
  1851. // This function adds an item to the movie's user data;
  1852. // the updated user data is written to the movie file when the movie is next updated
  1853. // (by calling AddMovieResource or UpdateMovieResource).
  1854. //
  1855. // NOTE: This function is intended to set the controller type of a movie you're building;
  1856. // to change the controller of an open movie, use QTUtils_ChangeControllerType.
  1857. //
  1858. //////////
  1859.  
  1860. OSErr QTUtils_SetControllerType (Movie theMovie, OSType theType)
  1861. {
  1862.     UserData        myUserData;
  1863.     OSErr            myErr = noErr;
  1864.  
  1865.     // make sure we've got a movie
  1866.     if (theMovie == NULL)
  1867.         return(paramErr);
  1868.         
  1869.     // get the movie's user data list
  1870.     myUserData = GetMovieUserData(theMovie);
  1871.     if (myUserData == NULL)
  1872.         return(paramErr);
  1873.     
  1874.     theType = EndianU32_NtoB(theType);
  1875.     myErr = SetUserDataItem(myUserData, &theType, sizeof(theType), kUserDataMovieControllerType, 0);
  1876.  
  1877.     return(myErr);
  1878. }
  1879.  
  1880.  
  1881. //////////
  1882. //
  1883. // QTUtils_ChangeControllerType
  1884. // Change the controller type of the movie that uses the specified controller, "on the fly",
  1885. // and return the new movie controller to the caller; if for some reason we cannot create a
  1886. // new movie controller, return NULL.
  1887. //
  1888. //////////
  1889.  
  1890. MovieController QTUtils_ChangeControllerType (MovieController theMC, OSType theType, long theFlags)
  1891. {
  1892.     MovieController        myMC = NULL;
  1893.     Movie                myMovie = NULL;
  1894.     Rect                myRect;
  1895.     OSErr                myErr = noErr;
  1896.  
  1897.     // make sure we've got a movie controller
  1898.     if (theMC == NULL)
  1899.         return(NULL);
  1900.     
  1901.     // get the movie associated with that controller
  1902.     myMovie = MCGetMovie(theMC);
  1903.     if (myMovie == NULL)
  1904.         return(NULL);
  1905.         
  1906.     GetMovieBox(myMovie, &myRect);
  1907.  
  1908.     // set the new controller type in the movie's user data list
  1909.     myErr = QTUtils_SetControllerType(myMovie, theType);
  1910.     if (myErr != noErr)
  1911.         return(NULL);
  1912.  
  1913.     // dispose of the existing controller
  1914.     DisposeMovieController(theMC);
  1915.     
  1916.     // create a new controller of the specified type
  1917.     myMC = NewMovieController(myMovie, &myRect, theFlags);
  1918.  
  1919.     return(myMC);
  1920. }
  1921.  
  1922.  
  1923. #endif    // ifndef __QTUtilities__
  1924.